package com.fvision.camera.service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.opengl.GLSurfaceView;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Build.VERSION;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.Toast;

import com.fvision.camera.BuildConfig;
import com.fvision.camera.Confecting;
import com.fvision.camera.MainActivity;
import com.fvision.camera.R;
import com.fvision.camera.iface.FroegroundIface;
import com.fvision.camera.manager.ActivityStackManager;
import com.fvision.camera.manager.CmdManager;
import com.fvision.camera.receiver.FroegroundReceiver;
import com.fvision.camera.utils.CameraStateUtil;
import com.fvision.camera.utils.Const;
import com.fvision.camera.utils.LogUtils;
import com.huiying.cameramjpeg.UvcCamera;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;

/**
 * Created by mayn on 2018/1/5.
 */

public class ForegroundService extends Service {
    private static final String TAG = "ForegroundService";
    private boolean mReflectFlg = false;
    private final IBinder mBinder = new ForegroundBinder();
    private static final int NOTIFICATION_ID = 1; // 如果id设置为0,会导致不能设置为前台service
    private static final Class<?>[] mSetForegroundSignature = new Class[]{
            boolean.class};
    private static final Class<?>[] mStartForegroundSignature = new Class[]{
            int.class, Notification.class};
    private static final Class<?>[] mStopForegroundSignature = new Class[]{
            boolean.class};
    private NotificationManager mNM;
    private Method mSetForeground;
    private Method mStartForeground;
    private Method mStopForeground;
    private Object[] mSetForegroundArgs = new Object[1];
    private Object[] mStartForegroundArgs = new Object[2];
    private Object[] mStopForegroundArgs = new Object[1];

    private long lastSyncTime = 0;
    //定义浮动窗口布局
    LinearLayout mFloatLayout;
    WindowManager.LayoutParams wmParams;
    //创建浮动窗口设置布局参数的对象
    WindowManager mWindowManager;
    private float mTouchStartX;
    private float mTouchStartY;
    private float x;
    private float y;
    private boolean initViewPlace = false;
    GLSurfaceView mFloatView;
    int stateHight = -1;
    private int doubleConut = 0;

    FroegroundReceiver receiver;
    FroegroundIface iface = new FroegroundIface() {
        @Override
        public void showPopuWindow() {
            createFloatView();
        }

        @Override
        public void hidePopuWindow() {
            hideFloatWindow();
        }

        @Override
        public void syncTime() {
            serviceSyncTime();
        }

        @Override
        public void pullUsb() {
            pull_usb();
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        startCamera();
        Log.d(TAG, "onCreate");
        receiver = new FroegroundReceiver(this, iface);
        receiver.registerReceiver();
        stateHight = getStateHight();
        mNM = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        try {
            mStartForeground = ForegroundService.class.getMethod("startForeground", mStartForegroundSignature);
            mStopForeground = ForegroundService.class.getMethod("stopForeground", mStopForegroundSignature);
        } catch (NoSuchMethodException e) {
            mStartForeground = mStopForeground = null;
        }

        try {
            mSetForeground = getClass().getMethod("setForeground",
                    mSetForegroundSignature);
        } catch (NoSuchMethodException e) {
            throw new IllegalStateException(
                    "OS doesn't have Service.startForeground OR Service.setForeground!");
        }

        Notification.Builder builder = new Notification.Builder(this);

        if (Build.VERSION.SDK_INT >= 26) {
            MainActivity.hasRun = 2;
            NotificationChannel channel = new NotificationChannel("616", "huiying", NotificationManager.IMPORTANCE_LOW);
            builder.setChannelId("616");
            mNM.createNotificationChannel(channel);
        }

        Intent intent = new Intent(this, MainActivity.class);
        Bundle bundle = new Bundle();
        bundle.putBoolean(Const.isPendingIntent, true);
        intent.putExtras(bundle);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, FLAG_UPDATE_CURRENT);
        builder.setContentIntent(contentIntent);
        builder.setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher));
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setTicker(getString(R.string.app_name));
        builder.setContentTitle(getString(R.string.app_name));
        //builder.setContentText("Make this service run in the foreground.");
        Notification notification = builder.build();

        startForegroundCompat(NOTIFICATION_ID, notification);
    }

    public void pull_usb() {
        LogUtils.d("pull_usb()");
        UvcCamera.getInstance().stopPreview();
        UvcCamera.getInstance().releaseUvccamera();
        ActivityStackManager.getManager().exitApp(this);
    }

    public void startCamera() {
        LogUtils.d("111111111 ForegroundService onCreate startCamera()");
        long now = System.currentTimeMillis();
        if (now - lastSyncTime < 1000 * 1) {
            return;
        }
        lastSyncTime = now;
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (!UvcCamera.getInstance().isInit()) {
                    UvcCamera.getInstance().setPkgName(BuildConfig.APPLICATION_ID);
                    if (Confecting.APP_UPGRADE_CHANNEL.equals(".px3")) {
                        UvcCamera.getInstance().initUvccameraByPath("/mnt/media_rw");
                    } else {
                        UvcCamera.getInstance().initUvccamera();
                    }
                }
                if (UvcCamera.getInstance().isInit()) {
                    if (!UvcCamera.getInstance().isPreviewing()) {
                        UvcCamera.getInstance().startPreview();
                    }
                    CmdManager.getInstance().syncTime();
                }
            }
        }).start();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        Log.d(TAG, "onStartCommand");
//        serviceSyncTime();
        startCamera();
        // createFloatView();
        return START_NOT_STICKY;
    }

    private void serviceSyncTime() {
//        LogUtils.write("synctime","111111 ForegroundService serviceSyncTime() syncTime()");
        if (!UvcCamera.getInstance().isInit()) {
            UvcCamera.getInstance().setPkgName(BuildConfig.APPLICATION_ID);
            UvcCamera.getInstance().initUvccamera();
        }
        if (UvcCamera.getInstance().isInit()) {
            CmdManager.getInstance().syncTime();
        }
    }

    /**
     * 判断当前时间是否正确
     *
     * @return
     */
    private boolean currentTimeIsRight() {
        long now = System.currentTimeMillis();
        Calendar calendar = Calendar.getInstance();
        calendar.set(2018, 0, 1);
        boolean is = now > calendar.getTimeInMillis();
        if (is == false) {
            LogUtils.e("时间错误,不同步 " + CameraStateUtil.longToString(now, null));
        }
        return is;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
        hideFloatWindow();
        stopForegroundCompat(NOTIFICATION_ID);
        receiver.unregisterReceiver();

        if (UvcCamera.getInstance().isInit() && UvcCamera.getInstance().isPreviewing()) {
            UvcCamera.getInstance().stopPreview();
        }
        UvcCamera.getInstance().releaseUvccamera();
    }

    private void initFloatView() {
        wmParams = new WindowManager.LayoutParams();
        //获取的是WindowManagerImpl.CompatModeWrapper
        mWindowManager = (WindowManager) getApplication().getSystemService(getApplication().WINDOW_SERVICE);
        Log.i(TAG, "mWindowManager--->" + mWindowManager);
        LogUtils.d(" Build.VERSION.SDK_INT " + Build.VERSION.SDK_INT);
        //设置window type
//        if (Build.VERSION.SDK_INT <=  Build.VERSION_CODES.KITKAT || Confecting.APP_UPGRADE_CHANNEL.equals(".px3")){
//            wmParams.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
//        }else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
//            wmParams.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;//TYPE_APPLICATION_OVERLAY TYPE_TOAST
//        }else {
//            wmParams.type = WindowManager.LayoutParams.TYPE_TOAST;
//        }
        if (Build.VERSION.SDK_INT >= 26) {//8.0新特性
            wmParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT || Confecting.APP_UPGRADE_CHANNEL.equals(".px3")) {
                wmParams.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
            } else {
                wmParams.type = WindowManager.LayoutParams.TYPE_TOAST;
            }
        }

        //设置图片格式，效果为背景透明
        wmParams.format = PixelFormat.RGBA_8888;
        //设置浮动窗口不可聚焦（实现操作除浮动窗口外的其他可见窗口的操作）
        wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        //调整悬浮窗显示的停靠位置为左侧置顶
        wmParams.gravity = Gravity.LEFT | Gravity.TOP;
        // 以屏幕左上角为原点，设置x、y初始值，相对于gravity
        wmParams.x = 0;
        wmParams.y = 0;

        //设置悬浮窗口长宽数据
        wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;

         /*// 设置悬浮窗口长宽数据
        wmParams.width = 200;
        wmParams.height = 80;*/

        LayoutInflater inflater = LayoutInflater.from(getApplication());
        //获取浮动窗口视图所在布局
        mFloatLayout = (LinearLayout) inflater.inflate(R.layout.float_layout, null);
        mFloatLayout.setVisibility(View.GONE);
        mFloatLayout.findViewById(R.id.take_picture).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                takePicture();
            }
        });
        //浮动窗口按钮
        mFloatView = (GLSurfaceView) mFloatLayout.findViewById(R.id.float_id);
        mFloatView.setEGLContextClientVersion(2);
        mFloatView.setRenderer(new GLSurfaceView.Renderer() {
            @Override
            public void onSurfaceCreated(GL10 gl, EGLConfig config) {
                UvcCamera.getInstance().initGles(1280, 720);
            }

            @Override
            public void onSurfaceChanged(GL10 gl, int width, int height) {
                UvcCamera.getInstance().changeESLayout(width, height);
            }

            @Override
            public void onDrawFrame(GL10 gl) {
                UvcCamera.getInstance().drawESFrame();
            }
        });
        mFloatLayout.measure(View.MeasureSpec.makeMeasureSpec(0,
                View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
                .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        Log.i(TAG, "Width/2--->" + mFloatView.getMeasuredWidth() / 2);
        Log.i(TAG, "Height/2--->" + mFloatView.getMeasuredHeight() / 2);
        //设置监听浮动窗口的触摸移动
        mFloatLayout.setOnTouchListener(new View.OnTouchListener() {
            float downX = 0, downY = 0;

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        downX = event.getX();
                        downY = event.getY();

                        if (!initViewPlace) {
                            initViewPlace = true;
                            //获取初始位置
                            mTouchStartX += (event.getRawX() - wmParams.x);
                            mTouchStartY += (event.getRawY() - wmParams.y);
                        } else {
                            //根据上次手指离开的位置与此次点击的位置进行初始位置微调
                            mTouchStartX += (event.getRawX() - x);
                            mTouchStartY += (event.getRawY() - y);
                        }

                        break;
                    case MotionEvent.ACTION_MOVE:
                        // TODO Auto-generated method stub
                        //getRawX是触摸位置相对于屏幕的坐标，getX是相对于按钮的坐标
                        x = event.getRawX();
                        y = event.getRawY();

                        wmParams.x = (int) (x - mTouchStartX);
                        wmParams.y = (int) (y - mTouchStartY);
                        mWindowManager.updateViewLayout(mFloatLayout, wmParams);

//                        float xOffset = event.getX() - (mFloatView.getMeasuredWidth()/2) ;
//                        float yOffset = event.getY() - (mFloatView.getMeasuredHeight()/2) ;
//                        wmParams.x = (int) event.getRawX() - mFloatView.getMeasuredWidth()/2;// -  (int)xOffset;
//
//                        //减25为状态栏的高度
//                        wmParams.y = (int) event.getRawY() - mFloatView.getMeasuredHeight()/2 - stateHight;// - (int)yOffset;
//                        Log.i(TAG, "RawX" + event.getRawX() + " RawY" + event.getRawY());
//                        Log.i(TAG, "X" + event.getX()+" Y" + event.getY());
//                        Log.i(TAG, "xOffset " + xOffset+" yOffset" + yOffset);
//                        Log.i(TAG, "mFloatView.getMeasuredWidth()/2 " + mFloatView.getMeasuredWidth()/2+" mFloatView.getMeasuredHeight()/2 " + mFloatView.getMeasuredHeight()/2);
//                        Log.i(TAG,"wmParams.x = "+wmParams.x + " wmParams.y "+wmParams.x +"\n");
//                        //刷新
//                        mWindowManager.updateViewLayout(mFloatLayout, wmParams);
                        break;
                    case MotionEvent.ACTION_UP:
                        doubleConut++;
                        startDoubleTimeoutThread();

                        if (doubleConut == 2) {
                            mHandler.removeCallbacks(clearDoubleThread);
                            Intent main = new Intent(ForegroundService.this, MainActivity.class);
                            main.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(main);
                            hideFloatWindow();
                        }
                        break;
                }

                return true;  //此处必须返回false，否则OnClickListener获取不到监听
            }
        });

        mFloatLayout.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Intent main = new Intent(ForegroundService.this, MainActivity.class);
                main.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(main);
                ForegroundService.this.stopSelf();
            }
        });
    }

    private void createFloatView() {
        if (mWindowManager == null || mFloatLayout == null) {
            initFloatView();
        }
        mFloatLayout.setVisibility(View.VISIBLE);
        //添加mFloatLayout
        mWindowManager.addView(mFloatLayout, wmParams);
    }

    public void hideFloatWindow() {
        if (mWindowManager != null && mFloatLayout.getVisibility() == View.VISIBLE) {
            mWindowManager.removeView(mFloatLayout);
            mFloatLayout.setVisibility(View.GONE);
        }
    }

    private void startDoubleTimeoutThread() {
        mHandler.postDelayed(clearDoubleThread, 1000);
    }

    private Runnable clearDoubleThread = new Runnable() {
        @Override
        public void run() {
            doubleConut = 0;
        }
    };

    private int getStateHight() {
        /**
         * 获取状态栏高度——方法1
         * */
        int statusBarHeight1 = -1;
        //获取status_bar_height资源的ID
        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            //根据资源ID获取响应的尺寸值
            statusBarHeight1 = getResources().getDimensionPixelSize(resourceId);
        }
        //LogUtils.d("状态栏高度:"+statusBarHeight1);
        return statusBarHeight1;
    }

    private Handler mHandler = new Handler();

    void invokeMethod(Method method, Object[] args) {
        try {
            method.invoke(this, args);
        } catch (InvocationTargetException e) {
            // Should not happen.
            Log.w("ApiDemos", "Unable to invoke method", e);
        } catch (IllegalAccessException e) {
            // Should not happen.
            Log.w("ApiDemos", "Unable to invoke method", e);
        }
    }

    /**
     * This is a wrapper around the new startForeground method, using the older
     * APIs if it is not available.
     */
    void startForegroundCompat(int id, Notification notification) {
        if (mReflectFlg) {
            // If we have the new startForeground API, then use it.
            if (mStartForeground != null) {
                mStartForegroundArgs[0] = Integer.valueOf(id);
                mStartForegroundArgs[1] = notification;
                invokeMethod(mStartForeground, mStartForegroundArgs);
                return;
            }

            // Fall back on the old API.
            mSetForegroundArgs[0] = Boolean.TRUE;
            invokeMethod(mSetForeground, mSetForegroundArgs);
            mNM.notify(id, notification);
        } else {
            /* 还可以使用以下方法，当sdk大于等于5时，调用sdk现有的方法startForeground设置前台运行，
             * 否则调用反射取得的sdk level 5（对应Android 2.0）以下才有的旧方法setForeground设置前台运行 */

            if (VERSION.SDK_INT >= 5) {
                startForeground(id, notification);
            } else {
                // Fall back on the old API.
                mSetForegroundArgs[0] = Boolean.TRUE;
                invokeMethod(mSetForeground, mSetForegroundArgs);
                mNM.notify(id, notification);
            }
        }
    }

    private void takePicture() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-kk-mm-ss-SSS");
                String name = format.format(new Date()) + ".jpg";
                final String path = Const.JPG_PATH + name;
                final boolean sucess = UvcCamera.getInstance().takeSnapshot(path);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (sucess) {
                            Toast.makeText(ForegroundService.this, R.string.take_snapshot_sucess, Toast.LENGTH_SHORT).show();
                        } else {
                            Toast.makeText(ForegroundService.this, R.string.take_snapshot_fail, Toast.LENGTH_SHORT).show();
                        }
                    }
                });
            }
        }).start();

    }

    /**
     * This is a wrapper around the new stopForeground method, using the older
     * APIs if it is not available.
     */
    void stopForegroundCompat(int id) {
        if (mReflectFlg) {
            // If we have the new stopForeground API, then use it.
            if (mStopForeground != null) {
                mStopForegroundArgs[0] = Boolean.TRUE;
                invokeMethod(mStopForeground, mStopForegroundArgs);
                return;
            }

            // Fall back on the old API.  Note to cancel BEFORE changing the
            // foreground state, since we could be killed at that point.
            mNM.cancel(id);
            mSetForegroundArgs[0] = Boolean.FALSE;
            invokeMethod(mSetForeground, mSetForegroundArgs);
        } else {
            /* 还可以使用以下方法，当sdk大于等于5时，调用sdk现有的方法stopForeground停止前台运行，
             * 否则调用反射取得的sdk level 5（对应Android 2.0）以下才有的旧方法setForeground停止前台运行 */

            if (VERSION.SDK_INT >= 5) {
                stopForeground(true);
            } else {
                // Fall back on the old API.  Note to cancel BEFORE changing the
                // foreground state, since we could be killed at that point.
                mNM.cancel(id);
                mSetForegroundArgs[0] = Boolean.FALSE;
                invokeMethod(mSetForeground, mSetForegroundArgs);
            }
        }
    }

    public class ForegroundBinder extends Binder {
        public ForegroundService getService() {
            return ForegroundService.this;
        }
    }
}
